package com.ego.item.service.impl;

import com.ego.common.utils.PageResult;
import com.ego.item.bo.SpuBo;
import com.ego.item.mapper.*;
import com.ego.item.pojo.*;
import com.ego.item.service.CategoryService;
import com.ego.item.service.GoodsService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Transactional
public class GoodsServiceImpl implements GoodsService {

    @Autowired(required = false)
    private SpuMapper spuMapper;

    @Autowired
    private CategoryService categoryService;

    @Autowired(required = false)
    private BrandMapper brandMapper;

    @Autowired(required = false)
    private SpuDetailMapper spuDetailMapper;

    @Autowired(required = false)
    private SkuMapper skuMapper;

    @Autowired(required = false)
    private StockMapper stockMapper;

    @Autowired
    private AmqpTemplate amqpTemplate;


    @Override
    public PageResult<SpuBo> querySpuByPageAndSort(Integer pageNo, Integer pageSize, Boolean saleable, String key) {
        PageHelper.startPage(pageNo, pageSize);
        Example example = new Example(Spu.class);
        Example.Criteria criteria = example.createCriteria();
        //看时候上架下架
        // System.out.println("============================================="+saleable);
        if (saleable != null) {
            criteria.orEqualTo("saleable", saleable);
        }
        //按照搜索条件查询
        if (StringUtils.isNotBlank(key)) {
            criteria.andLike("title", "%" + key + "%");
        }
        List<Spu> spus = this.spuMapper.selectByExample(example);
        //将spu转成spuBo,给前端渲染出来分类名称和品牌名称
        //这儿是用的一种工具,比较快捷(专门用来做数组呀,集合呀这些的转换)
        //当然也可以写一个循环,定义一个新集合来存放spubos,遍历上面spus,一个一个操作来分别加进去
        List<SpuBo> spuBos = spus.stream().map(new Function<Spu, SpuBo>() {//可以用lambda表达式来做的
            @Override
            public SpuBo apply(Spu spu) {
                SpuBo spuBo = new SpuBo();
                //将spu中的属性值拷贝到spubo中
                BeanUtils.copyProperties(spu, spuBo);
                // 查询spu的商品分类名称
                List<String> names = categoryService.queryNameByIds(
                        Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));
                // 将分类名称拼接后存入
                spuBo.setCname(StringUtils.join(names, "/"));
                Brand brand = brandMapper.selectByPrimaryKey(spu.getBrandId());
                spuBo.setBname(brand.getName());
                return spuBo;
            }
        }).collect(Collectors.toList());//收集到一个新的list里面,太帅了,比写循环快得多哦
        return new PageResult<>(new PageInfo<Spu>(spus).getTotal(), spuBos);
    }

    @Override
    public void saveGoods(SpuBo spuBo) {
        //保存spu基本
        spuBo.setSaleable(true);
        spuBo.setValid(true);
        spuBo.setCreateTime(new Date());
        spuBo.setLastUpdateTime(spuBo.getCreateTime());
        spuMapper.insertSelective(spuBo);
        spuBo.getSpuDetail().setSpuId(spuBo.getId());
        //保存spu详细信息
        spuDetailMapper.insert(spuBo.getSpuDetail());
        //保存sku和库存信息
        for (Sku sku : spuBo.getSkus()) {
            if (!sku.getEnable()) {//如果不可用的话
                continue;
            }
            // 保存sku
            sku.setSpuId(spuBo.getId());
            sku.setCreateTime(new Date());
            sku.setLastUpdateTime(new Date());
            this.skuMapper.insert(sku);
            // 保存sku对应的stock
            Stock stock = new Stock();
            stock.setSkuId(sku.getId());
            stock.setStock(sku.getStock().getStock());
            stockMapper.insert(stock);
        }
        //添加了商品向 交换机发送个消息
        this.sendMsgToMq(spuBo.getId(), "insert");
    }

    @Override
    public SpuDetail getCurSpuDetailById(Long id) {
        return spuDetailMapper.selectByPrimaryKey(id);
    }

    @Override
    public List<Sku> getCurSpuSkusById(Long spuId) {
        Example example = new Example(Sku.class);
        example.createCriteria().andEqualTo("spuId", spuId);
        List<Sku> skus = skuMapper.selectByExample(example);
        for (Sku sku :
                skus) {
            sku.setStock(stockMapper.selectByPrimaryKey(sku.getId()));
        }
        return skus;
    }

    //更新spu,spuDetail,sku,stock  传递过来的json数据一抹多
    @Override
    public void updateGoods(SpuBo spuBo) {

        //首先更新下基本信息tb_spu
        spuBo.setLastUpdateTime(new Date());
        this.spuMapper.updateByPrimaryKeySelective(spuBo);
        //再来更新下详细信息tb_spu_detail
        this.spuDetailMapper.updateByPrimaryKeySelective(spuBo.getSpuDetail());
        //再来操作下当前spu下面的一些skus
        /*for (Sku sku :
                spuBo.getSkus()) {
                这种方法,没操作成功,没有更新成功,而且还要先判断一下有没有新的sku添加进来,
                没有新的添加的话,是操作不了数据库的
            this.skuMapper.updateByPrimaryKeySelective(sku);
            this.stockMapper.updateByPrimaryKeySelective(sku.getStock());
        }*/

        //所以说、、、
        //先把原来的当前的spu下面的skus删了,然后再重新插入进去
        Example example = new Example(Sku.class);
        example.createCriteria().andEqualTo("spuId", spuBo.getId());
        List<Sku> skus = skuMapper.selectByExample(example);
        for (Sku sku :
                skus) {
            this.skuMapper.deleteByPrimaryKey(sku.getId());
            //还得删除下面的一些stock,库存信息
            this.stockMapper.deleteByPrimaryKey(sku.getId());
        }
        //然后来重新插入
        for (Sku sku :
                spuBo.getSkus()) {
            if (!sku.getEnable()) {
                continue;
            }
            // 保存sku
            sku.setSpuId(spuBo.getId());
            // 默认不参与任何促销
            sku.setCreateTime(new Date());
            sku.setLastUpdateTime(new Date());
            this.skuMapper.insert(sku);
            // 保存库存信息
            Stock stock = new Stock();
            stock.setSkuId(sku.getId());
            stock.setStock(sku.getStock().getStock());
            stockMapper.insert(stock);
        }

        //更新了向交换机发送消息
        this.sendMsgToMq(spuBo.getId(), "update");
    }

    @Override
    public void deleteCurGoodById(Long id) {
        //删除spu
        this.spuMapper.deleteByPrimaryKey(id);
        //删除spuDetail
        this.spuDetailMapper.deleteByPrimaryKey(id);
        //删除skus
        Example example = new Example(Sku.class);
        example.createCriteria().andEqualTo("spuId", id);
        List<Sku> skus = skuMapper.selectByExample(example);
        for (Sku sku :
                skus) {
            this.skuMapper.delete(sku);
            //删除每个sku对应的stock
            this.stockMapper.delete(sku.getStock());
        }

        //向交换机发送消息
        this.sendMsgToMq(id, "delete");

    }

    @Override
    public SpuBo queryGoodsById(Long spuId) {
        Spu spu = spuMapper.selectByPrimaryKey(spuId);
        SpuDetail spuDetail = spuDetailMapper.selectByPrimaryKey(spuId);
        SpuBo spuBo = new SpuBo();
        BeanUtils.copyProperties(spu, spuBo);
        List<String> names = categoryService.queryNameByIds(
                Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3()));
        spuBo.setCname(StringUtils.join(names, "/"));
        Brand brand = brandMapper.selectByPrimaryKey(spu.getBrandId());
        spuBo.setBname(brand.getName());
        spuBo.setSpuDetail(spuDetail);
        Example example = new Example(Sku.class);
        example.createCriteria().andEqualTo("spuId", spuId);
        List<Sku> skus = skuMapper.selectByExample(example);
        for (Sku sku :
                skus) {
            sku.setStock(stockMapper.selectByPrimaryKey(sku.getId()));
        }
        spuBo.setSkus(skus);
        return spuBo;
    }

    @Override
    public Sku getSkuBySkuId(Long skuId) {
        return this.skuMapper.selectByPrimaryKey(skuId);
    }

    //封装了一个方法,让商品在增删改的时候,向消息队列发送消息
    //操作的时候,传的是id到mq中,因为要是直接传一个对象的话,好像东西有点多诶
    //交换机的名字我们在yml那边配置了的
    public void sendMsgToMq(Long id, String type) {
        try {//保证其他业务还是能够正常的执行
            this.amqpTemplate.convertAndSend("item." + type, id);
        } catch (Exception e) {

        }
    }

}
